package com.soul.net.http;

import com.soul.enums.HttpContentType;
import com.soul.enums.RequestMethod;
import com.soul.enums.RequestProtocol;
import com.soul.interceptor.Interceptor;
import com.soul.net.Request;
import org.apache.http.impl.client.CloseableHttpClient;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 请求类
 */
public class HttpRequest implements Request {

    protected static final String CONTENT_TYPE = "Content-Type";
    protected static final String CONTENT_LENGTH = "Content-Length";
    
    private String url;
    private RequestMethod method;
    private RequestProtocol protocol;
    private String encoding;
    private HttpContentType httpContentType;
    
    private Map<String,String> headers;
    private Map<String,String> queryParams;
    private Map<String,String> pathParams;
    
    protected byte[] httpContent = null;
    protected Integer connectTimeout = null;
    protected Integer readTimeout = null;

    private Class<? extends Interceptor> excludeInterceptor;
    
    public HttpRequest(String url) {
        this.url = url;
        this.headers = new HashMap();
        this.queryParams = new HashMap<>();
    }

    public HttpRequest(String url, Map<String, String> headers) {
        this.url = url;
        if (null != headers) {
            this.headers = headers;
        }
    }

    public HttpRequest() {
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setMethod(RequestMethod method) {
        this.method = method;
    }

    @Override
    public RequestProtocol getProtocol() {
        return protocol;
    }

    public void setProtocol(RequestProtocol protocol) {
        this.protocol = protocol;
    }

    @Override
    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public HttpContentType getHttpContentType() {
        return httpContentType;
    }
    
    public void setHeaders(Map<String, String> headers) {
        this.headers = headers;
    }

    public void setHttpContent(byte[] httpContent) {
        this.httpContent = httpContent;
    }

    public void setHttpContentType(HttpContentType httpContentType) {
        this.httpContentType = httpContentType;
        if (null == this.httpContent && null == httpContentType) {
            this.headers.remove("Content-Type");
        } else {
            this.headers.put("Content-Type", this.getContentTypeValue(this.httpContentType, this.encoding));
        }
    }

    public RequestMethod getMethod() {
        return this.method;
    }

    public byte[] getHttpContent() {
        return this.httpContent;
    }

    public String getHeaderValue(String name) {
        return this.headers.get(name);
    }

    @Override
    public Integer getConnectTimeout() {
        return this.connectTimeout;
    }

    public void setConnectTimeout(Integer connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    @Override
    public Integer getReadTimeout() {
        return this.readTimeout;
    }

    public void setReadTimeout(Integer readTimeout) {
        this.readTimeout = readTimeout;
    }

    public void putHeader(String name, String value) {
        if (null != name && null != value) {
            this.headers.put(name, value);
        }
    }

    public Map<String, String> getPathParams() {
        return pathParams;
    }

    public void setPathParams(Map<String, String> pathParams) {
        this.pathParams = pathParams;
    }

    public void putPathParams(String name, String value) {
        if (null != name && null != value) {
            this.pathParams.put(name, value);
        }
    }

    public void setHttpContent(byte[] content, String encoding, HttpContentType contentType) {
        if (null == content) {
            this.headers.put(CONTENT_LENGTH, "0");
            this.headers.remove(CONTENT_TYPE);
            this.httpContentType = null;
            this.httpContent = null;
            this.encoding = null;
        } else {
            this.httpContent = content;
            this.encoding = encoding;
            String contentLen = String.valueOf(content.length);
            if (null != contentType) {
                this.httpContentType = contentType;
            } else {
                this.httpContentType = HttpContentType.OCTET_STREAM;
            }

            this.headers.put("Content-Length", contentLen);
            this.headers.put("Content-Type", this.getContentTypeValue(this.httpContentType, encoding));
        }
    }

    public Map<String, String> getHeaders() {
        return Collections.unmodifiableMap(this.headers);
    }

    private String getContentTypeValue(HttpContentType contentType, String encoding) {
        if (null != contentType && null != encoding) {
            return contentType.toString() + ";charset=" + encoding.toLowerCase();
        } else {
            return null != contentType ? contentType.toString() : null;
        }
    }

    public Map<String, String> getQueryParams() {
        return Collections.unmodifiableMap(this.queryParams);
    }

    public void setQueryParams(Map<String, String> queryParams) {
        this.queryParams = queryParams;
    }

    public void putQueryParams(String name, String value) {
        if (null != name && null != value) {
            this.queryParams.put(name, value);
        }
    }

    public Class<? extends Interceptor> getExcludeInterceptor() {
        return excludeInterceptor;
    }

    public void setExcludeInterceptor(Class<? extends Interceptor> excludeInterceptor) {
        this.excludeInterceptor = excludeInterceptor;
    }

    public CloseableHttpClient getHttpClient(){
        return new HttpClientBuilder()
                .socketTimeout(connectTimeout)
                .connectTimeout(connectTimeout)
                .connectionRequestTimeout(readTimeout)
                .build();
    }
    
}
